using System;
using System.Collections.Generic;

namespace Dino
{
    public class Configuration
    {
        private readonly IDictionary<Type, Func<IObjectContext>> _contextFactories = new Dictionary<Type, Func<IObjectContext>>();
        private bool _useTransactionScope;

        /// <summary>
        /// Configures the unit of work to wrap the commit operation within a transaction scope.   NOTE: This may require the use of MSDTC.
        /// </summary>
        public Configuration UsingTransactionScope()
        {
            _useTransactionScope = true;
            return this;
        }

        /// <summary>
        /// Configures the given context lazily into the UnitOfWork Context's
        /// </summary>
        /// <typeparam name="T">The Type of Context.  Will use default constructor.</typeparam>
        public Configuration WithContext<T>() where T : IObjectContext, new()
        {
            WithContext<T>(() => new T());
            return this;
        }

        /// <summary>
        /// Configures the given context lazily into the UnitOfWork Context's
        /// </summary>
        /// <typeparam name="T">The Type of Context</typeparam>
        /// <param name="factory">How to create an instance of this context</param>
        public Configuration WithContext<T>(Func<IObjectContext> factory)
        {
            if (!_contextFactories.ContainsKey(typeof(T)))
            {
                _contextFactories[typeof(T)] = factory;
            }
            return this;
        }

        /// <summary>
        /// Configures the given context instance into the UnitOfWork Context's
        /// </summary>
        /// <typeparam name="T">The Type of Context</typeparam>
        /// <param name="context">The instance to add</param>
        public Configuration WithContext<T>(IObjectContext context)
        {
            WithContext<T>(() => context);
            return this;
        }

        /// <summary>
        /// Initializes the configuration
        /// </summary>
        /// <returns>The instance of the UnitOfWork</returns>
        public UnitOfWork Initialize()
        {
            if (_useTransactionScope)
            {
                return new TransactionScopeUnitOfWork { ContextFactories = _contextFactories };
            }

            return new UnitOfWork { ContextFactories = _contextFactories };
        }
    }
}